package com.weilx959.spt.core.component;

import com.weilx959.spt.core.constants.CommonConstants;
import com.weilx959.spt.core.serialize.JavaSerializer;
import com.weilx959.spt.core.serialize.ValueDeserializer;
import com.weilx959.spt.core.serialize.ValueSerializer;
import javafx.beans.property.*;
import javafx.css.PseudoClass;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.layout.HBox;
import lombok.Getter;
import lombok.Setter;

import java.util.Objects;

/**
 * 父级表单项控件基类
 *
 * @param <T> 表单项值类型
 */
public abstract class ParentFormItemControl<T> extends HBox implements FormItemControl<T> {
    public static final PseudoClass PSEUDO_CLASS_MODIFIED = PseudoClass.getPseudoClass("modified");

    protected StringProperty label;

    @Getter
    @Setter
    protected String key;

    protected ObjectProperty<T> value;

    @Setter
    protected T oldValue;

    private BooleanProperty editable;

    @Setter
    private ValueSerializer<T> serializer;

    @Setter
    private ValueDeserializer<T> deserializer;

    @Setter
    @Getter
    private int colspan;

    @Setter
    @Getter
    private int rowspan;

    protected ParentFormItemControl() {
        // 容器
        super.setSpacing(10);
        super.setAlignment(Pos.CENTER);
        super.getStyleClass().add(CommonConstants.Style.FORM_ITEM_CONTAINER);
        valueProperty().addListener((observable, ov, nv) -> super.pseudoClassStateChanged(PSEUDO_CLASS_MODIFIED, isModified()));
        // ediable
        super.setDisable(Boolean.FALSE.equals(getEditable()));
        editableProperty().addListener((observable, ov, nv) -> super.setDisable(Boolean.FALSE.equals(nv)));
        // 默认序列化器
        JavaSerializer<T> javaSerializer = new JavaSerializer<>();
        this.serializer = javaSerializer;
        this.deserializer = javaSerializer;
    }

    @Override
    public String getLabel() {
        return labelProperty().get();
    }

    @Override
    public StringProperty labelProperty() {
        if (Objects.isNull(label)) {
            label = new SimpleStringProperty(this, "LABEL");
        }
        return label;
    }

    @Override
    public void setLabel(String label) {
        labelProperty().set(label);
    }

    @Override
    public T getValue() {
        return valueProperty().get();
    }

    @Override
    public ObjectProperty<T> valueProperty() {
        if (Objects.isNull(value)) {
            value = new SimpleObjectProperty<>(this, "value");
        }
        return value;
    }

    @Override
    public void setValue(T value) {
        valueProperty().set(value);
    }

    @Override
    public boolean isModified() {
        return !Objects.equals(oldValue, getValue());
    }

    @Override
    public void reset() {
        this.valueProperty().set(oldValue);
    }

    @Override
    public void submit() {
        this.oldValue = this.valueProperty().get();
        super.pseudoClassStateChanged(PSEUDO_CLASS_MODIFIED, false);
    }

    @Override
    public Node getControl() {
        return this;
    }

    @Override
    public String serialize(T value) {
        return serializer.serialize(value);
    }

    @Override
    public T deserialize(String value) {
        return deserializer.deserialize(value);
    }

    public BooleanProperty editableProperty() {
        if (Objects.isNull(editable)) {
            editable = new SimpleBooleanProperty(this, "EDITABLE", true);
        }
        return editable;
    }

    public void setEditable(boolean editable) {
        editableProperty().set(editable);
    }

    public boolean getEditable() {
        return editableProperty().get();
    }
}
